package com.coke.im.client;

import java.net.InetSocketAddress;

import com.coke.im.client.exception.MessageException;
import com.coke.im.client.listener.MessageListener;
import com.coke.im.client.net.IOClient;
import com.coke.im.client.stream.Message;
import com.coke.im.client.stream.MessageTemp;
import com.coke.im.client.type.ExecStatus;
import com.coke.im.client.type.MessageHeadConstant;
import com.coke.im.client.type.MessageStatus;
import com.coke.im.client.util.StringUtils;

public class IMClient {

	private String host;

	private int port;

	private String username;

	private String password;

	private int liveTime = 60000;

	private MessageListener messageListener;


	private IOClient ioClient;

	public void setMessageListener(MessageListener messageListener) {
		this.messageListener = messageListener;
	}

	public IMClient(String host, int port) {
		this.host = host;
		this.port = port;
	}

	public void setUser(String username, String password) {
		this.username = username;
		this.password = password;
	}

	public void setLiveTime(int liveTime) {
		this.liveTime = liveTime;
	}
	
	public String sendMessage(String userId,String body) throws Exception {
		Message msg = MessageTemp.sendMessage(userId, body);
		this.sendMessage(msg);
		return msg.getHead(MessageHeadConstant.MESSAGE_ID);
		
	}

	private void sendMessage(Message msg) throws Exception {
		ioClient.write(msg);
	}

	public  void start() throws Exception {
		
		synchronized(this) {
			ioClient = new IOClient();
			ioClient.start(new InetSocketAddress(this.host, this.port));
			if (messageListener != null) {
				messageListener.onExecStatus(ExecStatus.CONN_SUCCESS);
			}
			Message msg = ioClient.readMessage();
			if (StringUtils.equals(msg.getHead(MessageHeadConstant.TYPE), MessageHeadConstant.LOGIN)) {
				ioClient.write(MessageTemp.loginMessage(this.username, this.password, this.liveTime));
				Message logmsg = ioClient.readMessage();
				if (StringUtils.equals(logmsg.getHead(MessageHeadConstant.TYPE), MessageHeadConstant.LOGIN)&& StringUtils.equals(logmsg.getHead(MessageHeadConstant.STATUS), MessageHeadConstant.SUCCESS)) {
					messageListener.onExecStatus(ExecStatus.LOGIN_SUCCESS);
				} else {
					messageListener.onExecStatus(ExecStatus.LOGIN_FAIL);
					throw new MessageException(ExecStatus.LOGIN_FAIL);
				}
			} else {
				messageListener.onExecStatus(ExecStatus.MESSAGE_FORMAT_ERROR);
				ioClient.close();
				throw new MessageException(ExecStatus.MESSAGE_FORMAT_ERROR);
			}
			
			this.readMessage(ioClient);
			this.live(ioClient);
			
			
		}
		

	}
	
	
	private synchronized void readMessage(IOClient ioClient) {
		new Thread(new ReadMessage(ioClient)).start();
	}
	
	private synchronized void live(IOClient ioClient) {
		new Thread(new LiveRunnable(ioClient)).start();
	}
	
	
	
	
	private class LiveRunnable implements Runnable{

		private IOClient ioClient;
		
		public LiveRunnable(IOClient ioClient) {
			this.ioClient = ioClient;
		}
		
		
		@Override
		public void run() {
			while(true) {
				try {
					this.ioClient.write(MessageTemp.liveMessage());
				} catch (Exception e1) {
					break;
				}
				try {
					Thread.sleep(liveTime);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	

	private class ReadMessage implements Runnable {


		private IOClient ioClient;

		public ReadMessage( IOClient ioClient) {
			this.ioClient = ioClient;
		}

		@Override
		public void run() {
			while (true) {
				Message msg = ioClient.readMessage();
				if (msg == null) {
					break;
				} else {
					if(StringUtils.equals(msg.getHead(MessageHeadConstant.TYPE), MessageHeadConstant.MESSAGE)) {
						messageListener.onReceiveMessage(msg);
					}
					if(StringUtils.equals(msg.getHead(MessageHeadConstant.TYPE), MessageHeadConstant.TRACK)) {
						
						if(StringUtils.equals(msg.getHead(MessageHeadConstant.RESULT), MessageHeadConstant.SUCCESS)) {
							messageListener.onMessageSatus(msg.getHead(MessageHeadConstant.MESSAGE_ID), MessageStatus.SUCCESS);
						}
						if(StringUtils.equals(msg.getHead(MessageHeadConstant.RESULT), MessageHeadConstant.FAIL)) {
							messageListener.onMessageSatus(msg.getHead(MessageHeadConstant.MESSAGE_ID), MessageStatus.FAIL);
						}
						if(StringUtils.equals(msg.getHead(MessageHeadConstant.RESULT), MessageHeadConstant.NO_USER)) {
							messageListener.onMessageSatus(msg.getHead(MessageHeadConstant.MESSAGE_ID), MessageStatus.NOUSER);
						}
						
					}
				}
			}
			messageListener.onExecStatus(ExecStatus.CONN_BREAK);
		}

	}



	public void stop() {
		synchronized(this) {
			if(ioClient!=null) {
				try {
					ioClient.close();
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		
	}

}
